﻿// by Shimohana
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;

using AzukiMap.Tools.Logger;
using Geometries = GisSharpBlog.NetTopologySuite.Geometries;
using GisSharpBlog.NetTopologySuite.IO;
using GeoAPI.Geometries;
using AzukiMap.Tools;

namespace AzukiMap.Request
{
    public class MeshParser : IEnumerable
    {
        protected BinaryReader _geomReader;
        protected IGeometryFactory _geoFactory;
        protected int _currentReadingRecord;
        protected int _numOfObjects;
        protected int _errorCode;
//        PostGisRecord[] _records;
        Dictionary<int, string> _errorMessages;
        WKBReader _reader;
        private ImageBrush _imageBrush;

        private MeshDataSet<double> _meshDataSet;

        public MeshDataSet<double> MeshDataSet
        {
            get { return _meshDataSet; }
            set { _meshDataSet = value; }
        }

        public BinaryReader GeomReader
        {
            get { return _geomReader; }
        }
 
        public int NumOfObjects
        {
            get { return _numOfObjects; }
        }

        public int ErrorCode
        {
            get { return _errorCode; }
        }

        public MeshParser(BinaryReader geomReader)
        {
            Logger.Debug(
                "PostGisDataParser.PostGisDataParser(): "
                + " geomReader.BaseStreamLength: " + geomReader.BaseStream.Length
                );

            _geomReader = geomReader;
            _currentReadingRecord = 0;
            Geometries.PrecisionModel pm = new Geometries.PrecisionModel();
            _geoFactory = new Geometries.GeometryFactory(pm, -1);
            _reader = new WKBReader(_geoFactory);

            _meshDataSet = new MeshDataSet<double>();
            _meshDataSet.Read(_geomReader);


//            ParseHeader();
//            ParseRecords();
            InitErrorMessages(); 
        }

        public ImageBrush GetImageBrush()
        {
            if (_imageBrush == null)
            {
                _imageBrush = CreateImage();
            }
            return _imageBrush;
        }

        /// <summary>
        /// イメージブラシ作成
        /// </summary>
        /// <returns></returns>
        public ImageBrush CreateImage()
        {
            MeshDataSetHeader header = _meshDataSet.Header;
            double[] datas = _meshDataSet.Datas;
            int width = header.CountX;
            int height = header.CountY;
            WriteableBitmap wb = new WriteableBitmap(width, height);
            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    Color col;
                    if (datas[y * width + x] == double.MinValue)
                    {
                        col = Colors.Transparent;
                    }
                    else if (datas[y * width + x] > 0)
                    {
                        col = Colors.Blue;
                    }
                    else
                    {
                        col = Colors.Yellow;
                    }
                    byte[] cp = new byte[] { col.R, col.G, col.B, col.A };
                    int pixelValue = BitConverter.ToInt32(cp, 0);
                    wb.Pixels[y * width + x] = pixelValue;
                }
            }
            ImageBrush ib = new ImageBrush();
            ib.ImageSource = wb;
            wb.Invalidate();

            return ib;
        }

        void InitErrorMessages()
        {
            _errorMessages = new Dictionary<int, string>();
            _errorMessages.Add(0,"No Error");
            _errorMessages.Add(-1,"Database connection has a problem");
            _errorMessages.Add(-2,"Query has a error");
            _errorMessages.Add(-3,"Query process error");
            _errorMessages.Add(-11,"db parameter does not set");
            _errorMessages.Add(-12,"table parameter does not set");
            _errorMessages.Add(-13,"column parameter does net set");
            _errorMessages.Add(-14,"extent parameter does net set");
        }

        public bool HasError()
        {
            bool hasError = (_errorCode != 0);
            return hasError;
        }

        public string GetErrorMessage()
        {
            return _errorMessages[_errorCode];
        }

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new MeshDataEnum(_meshDataSet.Datas);
        }

        #endregion
    }

    public class MeshDataEnum : IEnumerator
    {
        double[] _records;
        int _pos = -1;
        bool _disposed = false;

        public MeshDataEnum(double[] records)
        {
            _records = records;
        }

        #region IEnumerator Members

        public object Current
        {
            get
            {
                try
                {
                    return _records[_pos];
                }
                catch (IndexOutOfRangeException ex)
                {
                    Logger.Error("PostGisDataEnum: IndexOutOfRangeException.", ex);
                    throw new InvalidOperationException();
                }
            }
        }

        public bool MoveNext()
        {
            if (_records == null)
            {
                return false;
            }
            _pos++;
            return (_pos < _records.Length);
        }

        public void Reset()
        {
            _pos = -1;
        }

        #endregion
    }

    public class NoMeshDataException : Exception
    {
        public NoMeshDataException(string message)
            : base(message)
        {
        }
    }

    public struct MeshData
    {
        public int Gid;
        public int ThemeId;
        public double Latitude;
        public double Longigude;
        public int[] Datas;
    }
}
